<template>
	<view>
		<!-- 搜索框 -->
		<view class="header">
			<!-- 搜索栏 -->
			<luyj-tree-search v-if="searchIf" :backgroundColor="searchBackgroundColor"
				:inputBackgroundColor="searchInputBackgroundColor" :radius="searchRadius" :iconColor="searchIconColor"
				:placeholder="searchPlaceholder" :placeholderStyle="searchPlaceholderStyle" :maxlength="searchMaxlength"
				:clearable="searchClearable" @confirm="confirmSearch"></luyj-tree-search>
			<!-- 面包屑导航 -->
			<luyj-tree-navigation :slabel="props.label" @inF="navigationInt" @clickItem="backTree">
			</luyj-tree-navigation>
			<!-- 面包屑导航 -->
		</view>
		<!-- 列表 -->
		<view>
			<view class="container-list" :style="{'padding-bottom' : isCheck ? '160rpx' : 0 , 'padding-top' :searchIf ? '200rpx' :'90rpx' }">
				<luyj-tree-item v-for="(item , index) in tree" :key="index" :item="item" :isCheck="isCheck"
					:checkActiveColor="checkActiveColor" :checkNoneColor="checkNoneColor" :multiple="props.multiple" :checked="isChecked(item)"
					 :nodes="props.nodes" :comparison="comparison" @clickItem="toChildren"
					@change="checkbox($event , item , index)">
					<template slot="body">
						<slot v-bind:item="item" v-bind:slotObj="slotObj" >
							<view class="word text-cut">{{ item[props.label] }}</view>
						</slot>
					</template>
				</luyj-tree-item>
			</view>
		</view>
		
		<!-- 确定按钮 -->
		<view v-if="isCheck" class="btn box_sizing">
			<button class="sureBtn" type="primary" @click="backConfirm">确认</button>
		</view>
	</view>
</template>

<script>
	/**
	 * luyj-tree 无限树形结构树、支持搜索选择。
	 * @description  无限树形结构组件。支持搜索、选择(包括单选、多选)。面包屑类型导航。原插件地址：https://ext.dcloud.net.cn/plugin?id=2423。
	 * @tutorial url https://ext.dcloud.net.cn/plugin?name=luyj-tree
	 * @property {Boolean} searchIf 是否开启搜索 （默认值true）
	 * @property {String} searchBackgroundColor 搜索框背景色(默认#FFFFFF)
	 * @property {String} searchInputBackgroundColor 搜索框的输入框背景色(默认#EEEFF0)
	 * @property {Number} searchRadius 搜索框的圆角值，单位rpx（默认40）
	 * @property {String} searchPlaceholder 搜索框的内容物空时提示内容
	 * @property {String} searchPlaceholderStyle 搜索框的placehoder的样式
	 * @property {Number} searchMaxlength 搜索框的最大输入长度 ,设置为 -1 的时候不限制最大长度
	 * @property {String} searchIconColor 搜索框的图标颜色（默认#B8B8B8）
	 * @property {Boolean} searchClearable 搜索框是否显示清除按钮
	 * @property {Array}  trees 传入的树形结构，每个对象必须包含唯一的id值(默认值【】)
	 * @property {Boolean} isCheck 是否开启选择操作（默认值false）
	 * @property {Object} slotObj 传入插槽的参数（因为插槽进行了循环，不能直接引用页面的参数，需要传递） 
	 * @property {Array} checkList 选中列表
	 * @property {Boolean} parent 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)(默认值false)
	 * @property {Array} parentList 父级列表
	 * @property {String} checkActiveColor 选中时单选框的颜色 (默认#00AAFF)
	 * @property {String} checkNoneColor 未选中时单选框的颜色（默认#B8B8B8) 
	 * @property {Object} props 参数配置。
	 *  @property {String} id id列的属性名称 
	 * 	@param {String}  label 指定选项标签为选项对象的某个属性值(默认值:name)
	 *  @param {String} children   指定选项的子选项为选项对象的某个属性名(默认值：children)
	 *  @param {Boolean} multiple 值为true时为多选，为false时是单选(默认值true)
	 *  @param {Boolean} checkStrictly(废弃) 需要在多选模式下才传该值，checkStrictly为false时，可让父子节点取消关联，选择任意一级选项。为true时关联子级，可以全选(默认值为false)
	 *  @param {Boolean} nodes  在单选模式下，nodes为false时，可以选择任意一级选项，nodes为true时，只能选择叶子节点(默认值为true) 
	 * @property {Boolean} stepReload 是否“分页加载”数据
	 * @property {Number} pageSize 分步加载生效时（当条数过大时，反应时间很长）
	 * @return {Function} clickItem 点击导航栏事件
	 * 	@value item 当前选中的item值
	 *  @value 	realHasChildren 是否包含子级
	 * @event {Function()} change 改变选择值时的方法
	 * @event {Function()} sendValue 提交选择的方法
	 * @event {Function()} backTree	选中导航栏时，返回其他层
	 */
	export default {
		name: "luyj-tree",
		props: {
			// 是否开启搜索
			searchIf: {
				type: Boolean,
				default: () => true
			},
			// 搜索框背景色
			searchBackgroundColor: {
				type: String,
				default: '#FFFFFF'
			},
			// 搜索框的输入框内背景颜色
			searchInputBackgroundColor: {
				type: String,
				default: '#EEEFF0'
			},
			// 搜索框的图标的颜色
			searchIconColor: {
				type: String,
				default: '#B8B8B8'
			},
			// 搜索框的圆角值，单位rpx
			searchRadius: {
				type: Number,
				default: 40
			},
			// 搜索框的提示placeholder内容
			searchPlaceholder: {
				type: String,
				default: '搜索'
			},
			// 搜索框的placeholder的样式
			searchPlaceholderStyle: {
				type: String,
				default: ''
			},
			// 搜索框最大输入长度 ,设置为 -1 的时候不限制最大长度
			searchMaxlength: {
				type: Number,
				default: 140
			},
			// 搜索框是否显示清除按钮
			searchClearable: {
				type: Boolean,
				default: true
			},
			// 传入的树形结构数据，每个对象必须包含唯一的id值
			trees: {
				type: Array,
				default: () => {
					return []
				}
			},
			//是否开启选择操作，值为false时仅展示，无操作
			isCheck: {
				type: Boolean,
				default: () => {
					return false
				}
			},
			// 传入插槽的其他参数
			slotObj: {
				type: Object,
				default :() =>{
					return null;
				}
			},
			// 选中列表
			checkList: {
				type: Array,
				default: () => []
			},
			// 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)
			parent: {
				type: Boolean,
				default: () => {
					return false
				}
			},
			// 父级列表
			parentList: {
				type: Array,
				default: () => []
			},
			// 选中时单选框的颜色
			checkActiveColor: {
				type: String,
				default: '#00AAFF'
			},
			// 未选中时单选框的颜色
			checkNoneColor: {
				type: String,
				default: '#B8B8B8'
			},
			// 树的属性参数
			props: {
				type: Object,
				default: () => {
					return {
						id: 'id',
						label: 'name',
						children: 'children',
						multiple: false,
						checkStrictly: false, //不关联
						nodes: false, // nodes为false时，可以选择任意一级选项；nodes为true时只能选择叶子节点
					}
				}
			},
			/**
			 * 是否懒加载树的值
			 */
			stepReload : {
				type:Boolean,
				default:false
			},
			// 每次循环加载的item的数据量
			pageSize : {
				type : Number,
				default:50
			}
		},
		data() {
			return {
				// 导航条
				setIsre: null, // 导航条方法 - 设置是否搜索中方法
				getIsre : null,	// 获取是否搜索中
				setTreeStack: null, // 导航条 - 设置导航
				concatTreeStack: null, // 导航条 - 拼接当前导航对象
				clearTreeStack: null, // 导航条- 清空导航条
				getTreeStack: null, // 导航条 - 获取导航条
				
				itemsLoading : false,	// item是否在循环渲染中
				itemsStop : false,		// 是否终止其他渲染
				tree: [],			// 默认数组
				newNum: 0,
				oldNum: 0,
				allData: this.trees,
				parent_data: this.parentList || [], //选择父辈
				searchResult: [],
				newCheckList: this.checkList,
				nodePathArray: [],					// 当前展示的路径
				// item名称对照表
				comparison: {
					value: this.props.id ? this.props.id : 'id', // 选中值名称
					label: this.props.label ? this.props.label : 'name', // 显示名称
					children: this.props.children ? this.props.children : 'children', // 子集名称
				}
			}
		},
		watch: {
			// 监听数据值的变化
			trees: function(val, oldval) {
				if (val != oldval) {
					var tree_stack = this.getTreeStack();
					this.allData = val;				// 重新加载所有树
					// 重新加载当前树
					if(!Array.isArray(tree_stack)){
						this.loadTree(val);
						return;
					}
					var length = tree_stack.length;
					if( length === 0){
						if(typeof(this.getIsre)  === "function"){
							if(this.getIsre()){
								return;
							}
						}
						this.loadTree(val);
					}else{
						let tempArray = val;		// 存储当前值
						let children = this.props.children;
						for(var i = 0 ; i < length ; i ++){
							var tempObject = tempArray.find(item=>{
								return tree_stack[i].Value == item.Value;
							});
							if(Boolean(tempObject)){
								tempArray = tempObject[children];
							}else{
								// 跳转到全部
								break;
							}
							if(i == length -1){
								this.loadTree(tempArray);
							}
						}
					}
				}
			},
			// 树的属性对照参数
			props: {
				handler: function(val) {
					this.comparison.value = this.props.id ? this.props.id : 'id';
					this.comparison.label = this.props.label ? this.props.label : 'name';
					this.comparison.children = this.props.children ? this.props.children : [];
				},
				deep: true
			},
			checkList: function(val , oldVal){
				if(val != oldVal){
					this.newCheckList = JSON.parse(JSON.stringify(val))
					return val;
				}
			}
		},
		created:function(){
			this.loadTree(this.trees);
		},
		// 实例被挂载后调用
		mounted() {
			let id = this.props.id;
			let children = this.props.children;
			// 关联子级的验证，暂时不使用
			// if (this.props.multiple && this.props.checkStrictly) {
			// 	if (this.newCheckList.length != 0) {
			// 		this.checkAllChoose();
			// 		return;
			// 	}
			// 	for (let i = 0; i < this.tree.length; i++) {
			// 		this.$set(this.tree[i], 'bx', 0)
			// 		this.$set(this.tree[i], 'qx', 0)
			// 	}
			// }
			// 初始化选中项
			if (!this.props.multiple && this.newCheckList.length > 0) {
				this.getNodeRoute(this.allData, this.newCheckList[0][id]);
				let arr = this.nodePathArray.reverse();
				if (arr.length == 0) {
					return;
				}
				
				this.concatTreeStack(arr);				// 获取导航条的值			
				// 加载当前列对应的数据
				var tree_stack = this.getTreeStack();
				var data = Boolean(tree_stack[tree_stack.length -1][children]) ? tree_stack[tree_stack.length - 1][
					children
				] : [];
				this.loadTree(data);
			}
		},
		methods: {
			// ========================================== 添加方法 =====================================================================
			/** 当前选项是否选中
			 * @param {Object} item
			 */
			isChecked(item){
				if(Array.isArray(this.newCheckList)){
					let id = this.props.id;
					let temp = this.newCheckList.find(chcked=>{
						return chcked[id] == item.id;
					});
					return Boolean(temp);
				}
				return false;
			},
			// =========================================== 初始化方法 ===================================================================
			/** 初始化导航条的方法
			 * @param {Object} e
			 */
			navigationInt: function(e) {
				this.setIsre = e.setIsre;
				this.getIsre = e.getIsre;
				this.concatTreeStack = e.concatTreeStack;
				this.pushTreeStack = e.pushTreeStack;
				this.clearTreeStack = e.clearTreeStack;
				this.getTreeStack = e.getTreeStack;
			},
			// =========================================== 监听事件 =====================================================================
			/** 选中当前的值
			 * @param {Object} e
			 * @param {Object} item 当前项
			 * @param {Object} index 低昂去索引
			 */
			checkbox(e, item, index) {
				var func = this.props.multiple ?  this.checkboxChange : this.radioChange;
				func(e,item ,index);			// 执行选择操作
			},
			/**单选
			 * @param {Object} e 点击事件
			 * @param {Object} item 当前项的值
			 * @param {Object} index 索引
			 */
			radioChange :function( e,item ,index){
				var that = this;
				if(e.detail.value){
					// 选中当前对象
					that.newCheckList = [];
					that.newCheckList.push(that.tree[index]);
				}else{
					// 移除其他对象
					var nIndex = that.newCheckList.indexOf(item);
					that.newCheckList.splice(nIndex , 1);
				}
				that.$emit('change', that.newCheckList);
			},
			/**异步检查复选框值的改变
			 * @param {Object} item
			 * @param {Object} index
			 * @param {Object} bx
			 * @param {Object} qx
			 */
			 async checkboxChange (e,item, index, bx, qx) {
				let that = this;
				let findIdex = that.newCheckList.indexOf(item);
				if(e.detail.value){
					// 点击选中
					if(findIdex == -1){
						that.newCheckList.push(that.tree[index]);
					}
				}else{
					// 点击不选
					that.newCheckList.splice(findIdex , 1);
				}
				that.$emit('change', that.newCheckList);
				
				// if (findIdex > -1) { //反选
				// 	if (that.props.checkStrictly) { //关联子级
				// 		if (item[props.hasChilren]) { //用户
				// 			that.newCheckList.splice(findIdex, 1)
				// 		} else { //非用户，取消所有下一级
				// 			if (Boolean(item[props.children])) {
				// 				that.getIdBydelete(item[props.children]);
				// 			}
				// 		}
				// 	} else {
				// 		that.newCheckList.splice(findIdex, 1)
				// 	}
				// } else { //选中
				// 	if (!item[this.props.hasChilren] && that.props.checkStrictly) { //选中下一级
				// 		if (qx || bx) { //取消下级
				// 			if (Boolean(item[props.children])) {
				// 				await that.getIdBydelete(item[props.children]);
				// 			}
				// 			item.qx = 0;
				// 			item.bx = 0;
				// 		} else {
				// 			item.qx = 1;
				// 			item.bx = 0;
				// 			if (Boolean(item[props.children])) {
				// 				await that.chooseChild(item[props.children], item[this.props.id]);
				// 			}
				// 		}
				// 		that.$emit('change', that.newCheckList);
				// 		// that.$forceUpdate()
				// 		return;
				// 	}
				// 	// if(item[this.props.hasChilren]&&this.props.checkStrictly) this.getNodeRoute(this.allData,item[this.props.id]);
				// 	that.newCheckList.push({
				// 		...item
				// 	});
				// }
				// that.$emit('change', that.newCheckList)
			},
			// 取消下一级的选中
			getIdBydelete(arr) {
				arr.forEach(e => {
					if (true) {
						for (var i = 0; i < this.newCheckList.length; i++) {
							// 包含下一级
							if (e[this.props.id] == this.newCheckList[i][this.props.id]) {
								this.newCheckList.splice(i, 1)
								break;
							}
						}
					}
					if (false) {
						// 不包含下一级
						if (Boolean(item[props.children])) {
							this.getIdBydelete(e[props.children]);
						}
					}
				})
			},
			// 关联下一级,选中
			chooseChild(arr, pid) {
				let that = this;
				for (var i = 0, len = arr.length; i < len; i++) {
					let item = arr[i];
					if (true) {
						// 包含下一级
						that.newCheckList.push({
							...item,
							tree_stackId: pid
						})
					}
					if (false) {
						// 不包含下一级
						// !item[that.props.hasChilren]
						if (Boolean(item[props.children])) {
							this.chooseChild(item[props.children], item[this.props.id])
						}
					}
				}
			},

			/** 
			 * @param {Array} tree 目标树
			 * @param {Object} targetId 为目标节点id
			 */
			getNodeRoute(tree, targetId) {
				let children = this.props.children;
				let id = this.props.id;
				for (let index = 0; index < tree.length; index++) {
					if (Boolean(tree[index][children]) ) {
						if (tree[index][children]) {
							let endRecursiveLoop = this.getNodeRoute(tree[index][children], targetId)
							if (endRecursiveLoop) {
								this.nodePathArray.push(tree[index]);
								return true;
							}
						}
					}
					if (tree[index][id] === targetId) {
						return true;
					}
				}
			},
			
			/**跳转到子级
			 * @param {Object} item 选中的项
			 * @param {Boolean} realHasChildren 是否包含子级
			 */
			toChildren(item, realHasChildren) {
				this.$emit("clickItem" , item , realHasChildren);		// 点击导航栏事件
				// 不包含子级,不执行任何操作
				if (!realHasChildren) {
					return;
				}
				// 点击跳转下一级
				let id = this.props.id;
				let children = this.props.children; // 子级名称

				// 将当前item加入到导航列表
				if (item[children].length > 0) {
					this.loadTree(item[children]);
					this.pushTreeStack(item); // 添加导航
				}
				// 关联数据 - 暂时不使用
				// if (this.props.checkStrictly) {
				// 	this.checkAllChoose();
				// }
			},
			/** 搜索提交方法
			 * @param {Object} e
			 */
			confirmSearch(e) {
				var val = e.detail.value;
				this.searchResult = [];
				// 查找
				uni.showLoading({
					title: '正在查找'
				});
				this.search(this.allData, val);
				// 返回搜索结果
				uni.hideLoading();
				this.setIsre(true); // 设置导航条为搜索状态
				this.clearTreeStack(); // 清空导航条
				this.loadTree(this.searchResult);
			},
			/**搜索方法
			 * @param {Object} data 搜索数据
			 * @param {Object} keyword 搜索关键字
			 */
			search(data, keyword) {
				var that = this;
				let children = that.props.children;
				for (var i = 0, len = data.length; i < len; i++) {
					// try-catch(try-catch) - 没有label列，跳过继续执行
					try{
						if (data[i][that.props.label].indexOf(keyword) >= 0) {
							that.searchResult.push(data[i]);
						}
						if (Boolean(data[i][children])) {
							if (data[i][children].length > 0) {
								that.search(data[i][children], keyword);
							}
						}
					}catch(e){
						console.warn(e);
					}
					
				}
			},
			/**
			 * 检查所有的选项
			 */
			checkAllChoose() {
				let o = false,
					t = true;
				this.tree.forEach((e, i) => {
					if (true) {
						// 包含下一级 !e[this.props.hasChilren]
						e.qx = o;
						e.bx = o;
						let num2 = this.computAllNumber(e[props.children]);
						// console.log(this.newNum,this.oldNum)
						if (this.newNum != 0 && this.oldNum != 0) {
							if (this.newNum == this.oldNum) {
								e.qx = t;
								e.bx = o;
							} else {
								e.qx = o;
								e.bx = t;
							}
						}
						if (this.newNum != 0 && this.oldNum == 0) {
							this.$set(this.tree[i], 'bx', o);
							this.$set(this.tree[i], 'qx', o);
						}
						// this.$forceUpdate()
						this.newNum = 0
						this.oldNum = 0
					}
				})
			},

			// 选中所选值
			computAllNumber(arr) {
				console.log("选中所选值");
				// for (let j = 0; j < arr.length; j++) {
				// 	var e = arr[j];
				// 	// if (arr[j][that.props.hasChilren]) {
				// 		this.newNum++;
				// 	// }
				// 	this.checkSum(e.id)
				// 	if (!e[that.props.hasChilren]) {
				// 		this.computAllNumber(e[props.children])
				// 	}
				// }
			},

			// 选中事件累计
			checkSum(id) {
				for (let i = 0; i < this.newCheckList.length; i++) {
					if (id == this.newCheckList[i].id) {
						this.oldNum++;
						break
					}
				}
			},

			/** 返回到其他树层
			 * @param {Object} item 当前item值
			 * @param {Object} index 返回到其他索引
			 */
			backTree(item, index) {
				this.$emit("backTree", item, index);
				let that = this;
				if (index == -1) {
					// 全部
					that.loadTree(that.allData);
				} else if (index == -2) {
					// 搜索
					that.loadTree(that.searchResult);		// 搜索结果
				} else {
					// 其他层级
					that.loadTree(item[that.props.children]);	// tree的其他层级
				}
				// 关联数据
				// if (this.props.checkStrictly) {
				// 	this.checkAllChoose();
				// }
			},
			/**
			 * 点击确认按钮执行事件
			 */
			backConfirm() {
				this.$emit('sendValue', this.newCheckList, 'back')
			},
			// ======================================== 公共方法 ===============================================================
			/**加载Tree值
			 * @param {Array} datas 待复制的数组
			 * @param {Number} start 起始位置
			 * @description 加载tree值。当数据量大时，子项加载时间很长。可以多次渲染加载
			 */
			loadTree : function(datas , start = 0 ){
				let that = this;
				if(!this.stepReload){
					// 不进行多次渲染加载
					that.tree = datas;
				}else{
					// datas为null, 不进行渲染
					if(!Array.isArray(datas)){
						that.tree = datas;
						return;
					}else if(datas.length === 0){
						that.tree = datas;
						return;
					}
					// 进行多次渲染加载
					if(start === 0){
						// 终止其他渲染
						if(that.itemsLoading){
							that.itemsStop = true;		//终止其他Item渲染
						}
						// 首次加载提醒
						uni.showLoading();
						that.tree = [];
						that.itemsLoading = true;
					}
					var length =  datas.length ;
					var end = Math.min(start + that.pageSize , length);
					var tempArray  = datas.slice(start , end);
					that.tree = that.tree.concat(tempArray);
					that.$nextTick(function(){
						if(start == 0){
							uni.hideLoading();
							that.itemsStop = false;
						}
						if(end < length && !that.itemsStop){
							that.loadTree(datas, end);
						}else{
							that.itemsLoading = false;
						}
					});
				}
			},
			// =================================================================================================================
			
		}
	}
</script>
<style lang="scss" scoped>
	@import "luyj-tree.scss";
	@import "icon.css";
</style>
